#ifndef COORDINATE_BASE_HPP
#define COORDINATE_BASE_HPP

#include "vec_operation.hpp"

/**
 * \brief coordinate base, create a orthonormal basis
 * \note
 * \tparam T type of the vector
 * \retval None
 */
template <typename T>
struct Coordinate_Base {
  using vec_type = tvec<T, 3>;

  // origin point
  vec_type _o;
  // frame
  struct _ONB {
    vec_type _u;
    vec_type _v;
    vec_type _w;
  };

  _ONB _basis_vecs;

  Coordinate_Base() : _o(), _basis_vecs{} {}

  Coordinate_Base( vec_type &a, vec_type &b, vec_type &c ) : _ONB{ a, b, c } {}

#define INIT_FROM_1( a, b, c, d )         \
  vec_type m( 0, 1, 0 ), n( 1, 0, 0 );    \
  a = normalize( d );                     \
  b = cross( a, n );                      \
  if ( b.squareLength() < FLT_EPSILON ) { \
    b = cross( a, m );                    \
  }

  void initFromU( vec_type &u ) {
    INIT_FROM_1( _basis_vecs._u, _basis_vecs._v, _basis_vecs._w, u )
    _basis_vecs._w = cross( _basis_vecs._u, _basis_vecs._v );
  }

  void initFromV( vec_type &v ) {
    INIT_FROM_1( _basis_vecs._v, _basis_vecs._u, _basis_vecs._w, v )
    _basis_vecs._w = cross( _basis_vecs._u, _basis_vecs._v );
  }

  void initFromW( vec_type &w ) {
    INIT_FROM_1( _basis_vecs._w, _basis_vecs._u, _basis_vecs._v, w )
    _basis_vecs._v = cross( _basis_vecs._w, _basis_vecs._u );
  }

#define INIT_FROM_2()
//   TODO: implement this 
  void initFromUV( vec_type &u, vec_type &v ) {}
  void initFromVU( vec_type &u, vec_type &v ) {}
  void initFromUW( vec_type &u, vec_type &w ) {}
  void initFromWU( vec_type &u, vec_type &w ) {}
  void initFromVW( vec_type &v, vec_type &w ) {}
  void initFromWV( vec_type &v, vec_type &w ) {}

  bool operator==( Coordinate_Base &base ) {
    return (_basis_vecs._u == base._basis_vecs._u) &&
           (_basis_vecs._v == base._basis_vecs._v) &&
           (_basis_vecs._w == base._basis_vecs._w)
  }

#undef INIT_FROM_1
#undef INIT_FROM_2
};

#endif